/*
 * Consola.c
 *
 *  Created on: 02/10/2011
 *      Author: utn_so
 */

#include "headers/GlobalHeader.h"

//Variables Globales

char comando[MAX_LINE];
int32_t i, salida;
FILE *stdin;
int32_t cabezalesPorCilindro;
int32_t sectoresPorPista;
int32_t cilindros;

int main(int argc, char *args[])
{
	int32_t sd, rc, contador, cantidadTotalSectores;
	sd = -1;
	struct sockaddr_un serveraddr;
	t_stream *streamEnvio;
	protocoloINFO_respuesta respuestaINFO;
	protocoloCLEAN_respuesta respuestaCLEAN;
	protocoloTRACE_respuesta respuestaTRACE;
	int32_t *ptrSectoresRecorridos;
	PPD_CHS sector;

	cabezalesPorCilindro = atoi(args[1]);
	sectoresPorPista = atoi(args[2]);
	cilindros = atoi(args[3]);
	cantidadTotalSectores = sectoresPorPista * cilindros;

	//Creo el socket de tipo UNIX
	sd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sd < 0){
		perror("socket() failed");
		return 0;
	}

	//Cargo el struct con la informacion del servidor
	memset(&serveraddr, 0, sizeof(serveraddr));
	serveraddr.sun_family = AF_UNIX;
	strcpy(serveraddr.sun_path, args[0]);

	rc = connect(sd, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr));
	if (rc<0){
		perror("connect() failed");
		return 0;
	}

	salida = FALSE;

	while(!salida)
	{
		printf("COMMAND-> ");
		fgets(comando,MAX_LINE,stdin);
		//PERMITO COMANDOS EN MAYUSCULA COMO EN MINUSCULA
		for (i = 0; comando[i];i++)
			comando[i] = tolower(comando[i]);

		if (!validoMedianteRegex(comando,"^tempo[[:blank:]][0-9]+[\n]"))
		{
			protocoloTRACE1 *pedidoTRACE1 = malloc(sizeof(protocoloTRACE1));
			pedido_t1 payload = armarStructTrace1(comando);

			pedidoTRACE1->cabecera.type = TEMPO;
			pedidoTRACE1->cabecera.payloadlength = sizeof(pedido_t1);
			pedidoTRACE1->payload.s1 = payload.s1;

			//serializo el pedido que armo con el pedido
			streamEnvio = PedidoTRACE1_serializer(pedidoTRACE1);

			//envio los bytes resultantes de la serializacion
			rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
			if (rc<0){
				perror("send() failed");
				return -1;
			}

			//libero los punteros dinamicos
			free(pedidoTRACE1);
			free(streamEnvio);
		}

		if (!validoMedianteRegex(comando,"^size[\n]"))
		{
			protocoloINFO *pedidoINFO = malloc(sizeof(protocoloINFO));

			pedidoINFO->cabecera.type = SIZEPEDIDOS;
			pedidoINFO->cabecera.payloadlength = 0;

			streamEnvio = PedidoINFO_serializer(pedidoINFO);

			rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
			if (rc<0){
				perror("send() failed");
				salida=TRUE;
				return -1;
			}

			free(pedidoINFO);
			free(streamEnvio);

			rc = recv(sd, &respuestaINFO.cabecera, sizeof(cabecera_paquete), MSG_WAITALL);
			if (rc<0){
				perror("recv() failed");
				salida=TRUE;
				return -1;
			}


			rc = recv(sd, &respuestaINFO.posicionActual, respuestaINFO.cabecera.payloadlength, MSG_WAITALL);
			if (rc<0){
				perror("recv() failed");
				salida=TRUE;
				return -1;
			}
			printf("Tamaño lista de pedidos: %d\n", respuestaINFO.posicionActual);
			printf("\n");
		}

		if (!validoMedianteRegex(comando,"^info[\n]"))
		{
			protocoloINFO *pedidoINFO = malloc(sizeof(protocoloINFO));

			pedidoINFO->cabecera.type = INFO;
			pedidoINFO->cabecera.payloadlength = 0;

			streamEnvio = PedidoINFO_serializer(pedidoINFO);

			rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
			if (rc<0){
				perror("send() failed");
				salida=TRUE;
				return -1;
			}

			free(pedidoINFO);
			free(streamEnvio);

			rc = recv(sd, &respuestaINFO.cabecera, sizeof(cabecera_paquete), MSG_WAITALL);
			if (rc<0){
				perror("recv() failed");
				salida=TRUE;
				return -1;
			}

			rc = recv(sd, &respuestaINFO.posicionActual, respuestaINFO.cabecera.payloadlength, MSG_WAITALL);
			if (rc<0){
				perror("recv() failed");
				salida=TRUE;
				return -1;
			}

			sector = ppd_LBAToCHS(respuestaINFO.posicionActual);

			printf("Posicion Actual: %d:%d\n", sector.cylinder, sector.sector);
			printf("\n");
		}

		if (!validoMedianteRegex(comando,"^clean[[:blank:]][0-9]+[[:blank:]][0-9]+[\n]"))
		{
			protocoloCLEAN *pedidoCLEAN = malloc(sizeof(protocoloCLEAN));
			pedido_clean payload = armarStructClean(comando);

			pedidoCLEAN->cabecera.type = CLEAN;
			pedidoCLEAN->cabecera.payloadlength = sizeof(pedido_clean);
			pedidoCLEAN->payload.sectorInicial = payload.sectorInicial;
			pedidoCLEAN->payload.sectorFinal = payload.sectorFinal;

			int32_t diferencia = diferenciaEntreSectores(ppd_LBAToCHS(payload.sectorInicial),ppd_LBAToCHS(payload.sectorFinal));
			int32_t contador = 0;
			int32_t cantidadOK = 0;

			streamEnvio = PedidoCLEAN_serializer(pedidoCLEAN);

			rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
			if (rc<0){
				perror("send() failed");
				salida=TRUE;
				return -1;
			}

			free(pedidoCLEAN);
			free(streamEnvio);

			while( contador < (diferencia + 1))
			{
				rc = recv(sd, &respuestaCLEAN, sizeof(cabecera_paquete), MSG_WAITALL);
				if (rc<0)
				{
					perror("recv() failed");
					salida=TRUE;
					return -1;
				}
				rc = recv(sd, &respuestaCLEAN.respuestaClean, respuestaCLEAN.cabecera.payloadlength, MSG_WAITALL);
				if (rc<0)
				{
					perror("recv() failed");
					salida=TRUE;
					return -1;
				}

				if (respuestaCLEAN.respuestaClean)
				{
					//sumo la variable
					cantidadOK++;
				}
				contador++;
			}

			if (cantidadOK == (diferencia + 1))
			{
				printf("Los sectores solicitados se han limpiado exitosamente\n");
			}
			else
			{
				printf("Algunos sectores no han podido ser limpiados\n");
			}
		}

		if (!validoMedianteRegex(comando,"^trace[[:blank:]][0-9]+[\n]"))
		{
			protocoloTRACE1 *pedidoTRACE1 = malloc(sizeof(protocoloTRACE1));
			pedido_t1 payload = armarStructTrace1(comando);

			if (payload.s1 < cantidadTotalSectores)
			{
				pedidoTRACE1->cabecera.type = TRACE1;
				pedidoTRACE1->cabecera.payloadlength = sizeof(pedido_t1);
				pedidoTRACE1->payload.s1 = payload.s1;

				//serializo el pedido que armo con el pedido
				streamEnvio = PedidoTRACE1_serializer(pedidoTRACE1);

				//envio los bytes resultantes de la serializacion
				rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
				if (rc<0)
				{
					perror("send() failed");
					salida=TRUE;
					return -1;
				}

				//libero los punteros dinamicos
				free(pedidoTRACE1);
				free(streamEnvio);

				//1ero recibo la cabecera de la respuesta del TRACE
				rc = recv(sd, &respuestaTRACE.cabecera, sizeof(cabecera_paquete),MSG_WAITALL);
				if (rc<0){
					perror("recv() failed");
					salida=TRUE;
					return -1;
				}

				//declaro un buffer que va a guardar toda la data que me envia despues de la cabecera
				char *buffer = malloc(respuestaTRACE.cabecera.payloadlength);

				//guardo todo en el buffer que aloque arriba
				rc = recv(sd, buffer, respuestaTRACE.cabecera.payloadlength,MSG_WAITALL);
				if (rc<0){
					perror("recv() failed");
					salida=TRUE;
					return -1;
				}

				//hago un memcpy de los primeros bytes que representan la parte estatica de la respuesta del TRACE, lo encapsulo en un tipo_respuesta_trace
				memcpy(&respuestaTRACE.payload, buffer, sizeof(respuestaTRACE.payload));

				//al puntero de sectoresRecorridos, lo hago apuntar a la posicion del buffer en la que empieza la parte dinamica
				int32_t size_dinamico = respuestaTRACE.cabecera.payloadlength - sizeof(respuestaTRACE.payload);

				ptrSectoresRecorridos = buffer + sizeof(respuestaTRACE.payload);

				//empiezo a mostrar por pantalla la informacion recibida en la respuesta
				sector = ppd_LBAToCHS(respuestaTRACE.payload.posicionActual);
				printf("Posicion actual: %d:%d\n", sector.cylinder, sector.sector);
				sector = ppd_LBAToCHS(respuestaTRACE.payload.sectorSolicitado);
				printf("Sector Solicitado: %d:%d\n", sector.cylinder, sector.sector);
				imprimeSectoresRecorridos(ptrSectoresRecorridos, size_dinamico);
				printf("Tiempo consumido: %f ms\n", respuestaTRACE.payload.tiempoConsumido);
				imprimirProximoSector(respuestaTRACE.payload.proximoSector);
				printf("\n");

				free(buffer);
			}
			else
			{
				printf("El nro de sector solicitado no corresponde a un sector valido\n");
			}
		}

		if (!validoMedianteRegex(comando,"^trace[[:blank:]][0-9]+[[:blank:]][0-9]+[\n]"))
		{
			protocoloTRACE2 *pedidoTRACE2 = malloc(sizeof(protocoloTRACE2));
			pedido_t2 payload = armarStructTrace2(comando);

			if (payload.s1 < cantidadTotalSectores && payload.s2 < cantidadTotalSectores)
			{

				pedidoTRACE2->cabecera.type = TRACE2;
				pedidoTRACE2->cabecera.payloadlength = sizeof(pedido_t2);
				pedidoTRACE2->payload.s1 = payload.s1;
				pedidoTRACE2->payload.s2 = payload.s2;

				//serializo el pedido que armo con el pedido
				streamEnvio = PedidoTRACE2_serializer(pedidoTRACE2);

				//envio los bytes resultantes de la serializacion
				rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
				if (rc<0){
					perror("send() failed");
					salida=TRUE;
					return -1;
				}

				//libero los punteros dinamicos
				free(pedidoTRACE2);
				free(streamEnvio);

				contador = 0;

				while(contador<2)
				{
					//1ero recibo la cabecera de la respuesta del TRACE
					rc = recv(sd, &respuestaTRACE.cabecera, sizeof(cabecera_paquete),MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//declaro un buffer que va a guardar toda la data que me envia despues de la cabecera
					char *buffer = malloc(respuestaTRACE.cabecera.payloadlength);

					//guardo todo en el buffer que aloque arriba
					rc = recv(sd, buffer, respuestaTRACE.cabecera.payloadlength,MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//hago un memcpy de los primeros bytes que representan la parte estatica de la respuesta del TRACE, lo encapsulo en un tipo_respuesta_trace
					memcpy(&respuestaTRACE.payload, buffer, sizeof(respuestaTRACE.payload));

					//al puntero de sectoresRecorridos, lo hago apuntar a la posicion del buffer en la que empieza la parte dinamica
					int32_t size_dinamico = respuestaTRACE.cabecera.payloadlength - sizeof(respuestaTRACE.payload);

					ptrSectoresRecorridos = buffer + sizeof(respuestaTRACE.payload);

					//empiezo a mostrar por pantalla la informacion recibida en la respuesta
					sector = ppd_LBAToCHS(respuestaTRACE.payload.posicionActual);
					printf("Posicion actual: %d:%d\n", sector.cylinder, sector.sector);
					sector = ppd_LBAToCHS(respuestaTRACE.payload.sectorSolicitado);
					printf("Sector Solicitado: %d:%d\n", sector.cylinder, sector.sector);
					imprimeSectoresRecorridos(ptrSectoresRecorridos, size_dinamico);
					printf("Tiempo consumido: %f ms\n", respuestaTRACE.payload.tiempoConsumido);
					imprimirProximoSector(respuestaTRACE.payload.proximoSector);
					printf("\n");

					free(buffer);
					contador++;
				}
			}
			else
			{
				printf("Uno de los sectores solicitados no corresponde a un sector valido, vuelva a intentarlo.\n");
			}
		}

		if (!validoMedianteRegex(comando,"^trace[[:blank:]][0-9]+[[:blank:]][0-9]+[[:blank:]][0-9]+[\n]"))
		{
			protocoloTRACE3 *pedidoTRACE3 = malloc(sizeof(protocoloTRACE3));
			pedido_t3 payload = armarStructTrace3(comando);

			if (payload.s1 < cantidadTotalSectores && payload.s2 < cantidadTotalSectores && payload.s3 < cantidadTotalSectores)
			{

				pedidoTRACE3->cabecera.type = TRACE3;
				pedidoTRACE3->cabecera.payloadlength = sizeof(pedido_t3);
				pedidoTRACE3->payload.s1 = payload.s1;
				pedidoTRACE3->payload.s2 = payload.s2;
				pedidoTRACE3->payload.s3 = payload.s3;

				streamEnvio = PedidoTRACE3_serializer(pedidoTRACE3);

				rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
				if (rc<0){
					perror("send() failed");
					salida=TRUE;
					return -1;
				}
				free(pedidoTRACE3);
				free(streamEnvio);

				contador = 0;

				while(contador < 3)
				{
					//1ero recibo la cabecera de la respuesta del TRACE
					rc = recv(sd, &respuestaTRACE.cabecera, sizeof(cabecera_paquete),MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//declaro un buffer que va a guardar toda la data que me envia despues de la cabecera
					char *buffer = malloc(respuestaTRACE.cabecera.payloadlength);

					//guardo todo en el buffer que aloque arriba
					rc = recv(sd, buffer, respuestaTRACE.cabecera.payloadlength,MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//hago un memcpy de los primeros bytes que representan la parte estatica de la respuesta del TRACE, lo encapsulo en un tipo_respuesta_trace
					memcpy(&respuestaTRACE.payload, buffer, sizeof(respuestaTRACE.payload));

					//al puntero de sectoresRecorridos, lo hago apuntar a la posicion del buffer en la que empieza la parte dinamica
					int32_t size_dinamico = respuestaTRACE.cabecera.payloadlength - sizeof(respuestaTRACE.payload);

					ptrSectoresRecorridos = buffer + sizeof(respuestaTRACE.payload);

					//empiezo a mostrar por pantalla la informacion recibida en la respuesta
					sector = ppd_LBAToCHS(respuestaTRACE.payload.posicionActual);
					printf("Posicion actual: %d:%d\n", sector.cylinder, sector.sector);
					sector = ppd_LBAToCHS(respuestaTRACE.payload.sectorSolicitado);
					printf("Sector Solicitado: %d:%d\n", sector.cylinder, sector.sector);
					imprimeSectoresRecorridos(ptrSectoresRecorridos, size_dinamico);
					printf("Tiempo consumido: %f ms\n", respuestaTRACE.payload.tiempoConsumido);
					sector = ppd_LBAToCHS(respuestaTRACE.payload.proximoSector);
					imprimirProximoSector(respuestaTRACE.payload.proximoSector);
					printf("\n");

					free(buffer);
					contador++;
				}
			}
			else
			{
				printf("Uno de los sectores solicitados no corresponde a un sector valido, vuelva a intentarlo.\n");
			}
		}

		if (!validoMedianteRegex(comando,"^trace[[:blank:]][0-9]+[[:blank:]][0-9]+[[:blank:]][0-9]+[[:blank:]][0-9]+[\n]"))
		{
			protocoloTRACE4 *pedidoTRACE4 = malloc(sizeof(protocoloTRACE4));
			pedido_t4 payload = armarStructTrace4(comando);

			if (payload.s1 < cantidadTotalSectores && payload.s2 < cantidadTotalSectores && payload.s3 < cantidadTotalSectores && payload.s4 < cantidadTotalSectores)
			{

				pedidoTRACE4->cabecera.type = TRACE4;
				pedidoTRACE4->cabecera.payloadlength = sizeof(pedido_t4);
				pedidoTRACE4->payload.s1 = payload.s1;
				pedidoTRACE4->payload.s2 = payload.s2;
				pedidoTRACE4->payload.s3 = payload.s3;
				pedidoTRACE4->payload.s4 = payload.s4;

				streamEnvio = PedidoTRACE4_serializer(pedidoTRACE4);

				rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
				if (rc<0){
					perror("send() failed");
					salida=TRUE;
					return -1;
				}

				free(pedidoTRACE4);
				free(streamEnvio);

				contador=0;

				while(contador < 4)
				{
					//1ero recibo la cabecera de la respuesta del TRACE
					rc = recv(sd, &respuestaTRACE.cabecera, sizeof(cabecera_paquete),MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//declaro un buffer que va a guardar toda la data que me envia despues de la cabecera
					char *buffer = malloc(respuestaTRACE.cabecera.payloadlength);

					//guardo todo en el buffer que aloque arriba
					rc = recv(sd, buffer, respuestaTRACE.cabecera.payloadlength,MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//hago un memcpy de los primeros bytes que representan la parte estatica de la respuesta del TRACE, lo encapsulo en un tipo_respuesta_trace
					memcpy(&respuestaTRACE.payload, buffer, sizeof(respuestaTRACE.payload));

					//al puntero de sectoresRecorridos, lo hago apuntar a la posicion del buffer en la que empieza la parte dinamica
					int32_t size_dinamico = respuestaTRACE.cabecera.payloadlength - sizeof(respuestaTRACE.payload);

					ptrSectoresRecorridos = buffer + sizeof(respuestaTRACE.payload);

					//empiezo a mostrar por pantalla la informacion recibida en la respuesta
					sector = ppd_LBAToCHS(respuestaTRACE.payload.posicionActual);
					printf("Posicion actual: %d:%d\n", sector.cylinder, sector.sector);
					sector = ppd_LBAToCHS(respuestaTRACE.payload.sectorSolicitado);
					printf("Sector Solicitado: %d:%d\n", sector.cylinder, sector.sector);
					imprimeSectoresRecorridos(ptrSectoresRecorridos, size_dinamico);
					printf("Tiempo consumido: %f ms\n", respuestaTRACE.payload.tiempoConsumido);
					sector = ppd_LBAToCHS(respuestaTRACE.payload.proximoSector);
					imprimirProximoSector(respuestaTRACE.payload.proximoSector);
					printf("\n");

					free(buffer);
					contador++;
				}
			}
			else
			{
				printf("Uno de los sectores solicitados no corresponde a un sector valido, vuelva a intentarlo.\n");
			}
		}

		if (!validoMedianteRegex(comando,"^trace[[:blank:]][0-9]+[[:blank:]][0-9]+[[:blank:]][0-9]+[[:blank:]][0-9]+[[:blank:]][0-9]+[\n]"))
		{
			protocoloTRACE5 *pedidoTRACE5 = malloc(sizeof(protocoloTRACE5));
			pedido_t5 payload = armarStructTrace5(comando);

			if (payload.s1 < cantidadTotalSectores && payload.s2 < cantidadTotalSectores && payload.s3 < cantidadTotalSectores && payload.s4 < cantidadTotalSectores && payload.s5 < cantidadTotalSectores)
			{
				pedidoTRACE5->cabecera.type = TRACE5;
				pedidoTRACE5->cabecera.payloadlength = sizeof(pedido_t5);
				pedidoTRACE5->payload.s1 = payload.s1;
				pedidoTRACE5->payload.s2 = payload.s2;
				pedidoTRACE5->payload.s3 = payload.s3;
				pedidoTRACE5->payload.s4 = payload.s4;
				pedidoTRACE5->payload.s5 = payload.s5;

				streamEnvio = PedidoTRACE5_serializer(pedidoTRACE5);

				rc = send(sd, streamEnvio->data, streamEnvio->length, 0);
				if (rc<0){
					perror("send() failed");
					salida=TRUE;
					return -1;
				}

				free(pedidoTRACE5);
				free(streamEnvio);

				contador = 0;

				while(contador < 5)
				{
					//1ero recibo la cabecera de la respuesta del TRACE
					rc = recv(sd, &respuestaTRACE.cabecera, sizeof(cabecera_paquete),MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//declaro un buffer que va a guardar toda la data que me envia despues de la cabecera
					char *buffer = malloc(respuestaTRACE.cabecera.payloadlength);

					//guardo todo en el buffer que aloque arriba
					rc = recv(sd, buffer, respuestaTRACE.cabecera.payloadlength,MSG_WAITALL);
					if (rc<0){
						perror("recv() failed");
						salida=TRUE;
						return -1;
					}

					//hago un memcpy de los primeros bytes que representan la parte estatica de la respuesta del TRACE, lo encapsulo en un tipo_respuesta_trace
					memcpy(&respuestaTRACE.payload, buffer, sizeof(respuestaTRACE.payload));

					//al puntero de sectoresRecorridos, lo hago apuntar a la posicion del buffer en la que empieza la parte dinamica
					int32_t size_dinamico = respuestaTRACE.cabecera.payloadlength - sizeof(respuestaTRACE.payload);

					ptrSectoresRecorridos = buffer + sizeof(respuestaTRACE.payload);

					//empiezo a mostrar por pantalla la informacion recibida en la respuesta
					sector = ppd_LBAToCHS(respuestaTRACE.payload.posicionActual);
					printf("Posicion actual: %d:%d\n", sector.cylinder, sector.sector);
					sector = ppd_LBAToCHS(respuestaTRACE.payload.sectorSolicitado);
					printf("Sector Solicitado: %d:%d\n", sector.cylinder, sector.sector);
					imprimeSectoresRecorridos(ptrSectoresRecorridos, size_dinamico);
					printf("Tiempo consumido: %f ms\n", respuestaTRACE.payload.tiempoConsumido);
					imprimirProximoSector(respuestaTRACE.payload.proximoSector);
					printf("\n");

					free(buffer);
					contador++;
				}
			}
			else
			{
				printf("Uno de los sectores solicitados no corresponde a un sector valido, vuelva a intentarlo.\n");
			}
		}
		if(sd == -1)
		{
			close(sd);
			exit(1);
		}

	}
	return 0;
}

